// You have generated a new plugin project without
// specifying the `--platforms` flag. A plugin project supports no platforms is generated.
// To add platforms, run `flutter create -t plugin --platforms <platforms> .` under the same
// directory. You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms.

import 'dart:async';
import 'dart:ffi';
import 'ifengdef.dart';
import 'package:flutter/services.dart';
import 'dart:convert' as convert;
import 'package:date_format/date_format.dart';

class Ifengtool {
  //通道
  static const MethodChannel _methodChannel =
      const MethodChannel('plugins.flutter.io.ifengtool/method');
  static const EventChannel _eventChannel =
      const EventChannel('plugins.flutter.io.ifengtool/event');
  static const MethodChannel _meChannel =
      const MethodChannel('plugins.flutter.io.ifengtool/event');

  //单例
  static Ifengtool? _instance;
  static Ifengtool getInstance() {
    if (_instance == null) {
      _instance = Ifengtool();
    }
    return _instance!;
  }

  bool _pluginInstalled = true; //plugin 是否安装了
  bool _isLogin = true;

  void initTestMode() {
    _pluginInstalled = false;
  }

  //test模式下 有用
  void initNoLogin() {
    if (_pluginInstalled) return;
    _isLogin = false;
  }

  IfengDeviceInfo? _deviceInfo;
  IfengPageInfo? _pageInfo;
  IfengUserInfo? _userInfo;
  IfengRightInfo? _rightInfo; //权限
  bool _forbiddenleftslide = false;

  Future<IfengDeviceInfo> getDeviceInfo({bool ignoreCache = false}) async {
    if (!ignoreCache && _deviceInfo != null) {
      return Future.value(_deviceInfo);
    }
    if (_pluginInstalled) {
      Map map = await _methodChannel.invokeMethod("deviceInfo");
      _deviceInfo = IfengDeviceInfo.fromMap(map);
    } else {
      _deviceInfo = IfengDeviceInfo.fromTestData();
    }

    return _deviceInfo!;
  }

  Future<IfengUserInfo> getUserInfo({bool ignoreCache = false}) async {
    if (!ignoreCache && _userInfo != null) {
      return Future.value(_userInfo);
    }
    if (_pluginInstalled) {
      Map map = await _methodChannel.invokeMethod("userInfo");
      _userInfo = IfengUserInfo.fromMap(map);
    } else {
      _userInfo = _isLogin ? IfengUserInfo.fromTestData() : IfengUserInfo();
    }

    return _userInfo!;
  }

  Future<IfengPageInfo> getPageInfo({bool ignoreCache = false}) async {
    if (!ignoreCache && _pageInfo != null) {
      return Future.value(_pageInfo);
    }
    if (_pluginInstalled) {
      Map map = await _methodChannel.invokeMethod("pageInfo");
      _pageInfo = IfengPageInfo.fromMap(map);
    } else {
      _pageInfo = IfengPageInfo.fromTestData();
    }

    return _pageInfo!;
  }

  Future<IfengRightInfo> getRightInfo({bool ignoreCache = true}) async {
    if (!ignoreCache && _rightInfo != null) {
      return Future.value(_rightInfo);
    }
    if (_pluginInstalled) {
      Map map = await _methodChannel.invokeMethod("rightInfo");
      _rightInfo = IfengRightInfo.fromMap(map);
    } else {
      _rightInfo = IfengRightInfo();
    }

    return _rightInfo!;
  }

  Future<IfengThemeMode> getShowMode() async {
    IfengDeviceInfo info = await getDeviceInfo();
    return info.mode;
  }

  Future<bool> goTo(Map args) async {
    return await _methodChannel.invokeMethod(
        "flutterGoTo", {'map': args, "json": convert.jsonEncode(args)});
  }

  Future<bool> login() async {
    if (!_pluginInstalled) {
      return Future.value((_isLogin = true));
    }
    return await _methodChannel.invokeMethod("login");
  }

  /*绑定手机号
  * */
  Future<bool> userBind() async {
    if (!_pluginInstalled) return Future.value(true);
    return await _methodChannel.invokeMethod("userBind");
  }

  /*是否认证
  * */
  Future<bool> isBindPhone() async {
    if (!_pluginInstalled) return Future.value(true);
    return await _methodChannel.invokeMethod("isBindPhone");
  }

  /*投屏
  * {
  *   'playTime':2.3,  //当前播放时间
  *    'videoConfig':{}//投屏数据
  *  }
  * **/
  Future<bool> projectScreen(Map map) async {
    return await _methodChannel.invokeMethod('projectScreen', map);
  }

  /*申请系统权限
  * */
  Future<bool> requestAuthority(IfengPremissionType type) async {
    if (!_pluginInstalled) return false;
    return await _methodChannel.invokeMethod(
        "requestAuthority", {"premissionType": type.displayTitle});
  }

  /*获取代理配置*/
  Future<IfengNetProxy?> netProxy() async {
    if (!_pluginInstalled) return Future.value(null);
    dynamic res = await _methodChannel.invokeMethod("netProxy");
    Map mp = res;
    return (mp.isNotEmpty ? IfengNetProxy(mp['host'], mp['port']) : null);
  }

  /*卡片分享
  * **/
  Future<bool> shareWebCard(IfengShareBean bean) async {
    return await _methodChannel.invokeMethod("shareWebCard", bean.toMap());
  }

  /*分享
  * **/
  Future<bool> openShare(IfengShareBean bean) async {
    return await _methodChannel.invokeMethod("openShare", bean.toMap());
  }

  /*禁止左滑退出
  * **/
  Future<bool> forbiddenLeftSlide(bool forbidden) async {
    _forbiddenleftslide = forbidden;
    return await _methodChannel
        .invokeMethod("forbiddenLeftSlide", {'forbidden': forbidden});
    ;
  }

  /*获取是否禁止左滑退出
  * **/
  bool getForbiddenLeftSlideState() {
    return _forbiddenleftslide;
  }

  /*获取地理位置 返回null 代表 没有获取地理位置
  * **/
  Future<IfengLocation> getLocation() async {
    if (_pluginInstalled) {
      return Future.value(IfengLocation.fromMap(
          await _methodChannel.invokeMethod("getLocation")));
    } else {
      return Future.value(IfengLocation.fromMap({
        'longitude': 116.49692124454602,
        'latitude': 40.01112746909426,
        "name": '启阳路',
        "lastCity": '北京市',
        'lastState': '北京市',
        'country': '中国'
      }));
    }
  }

  /*发送统计
  ***/
  Future<bool> stat(String statType, Map map) async {
    if (_pluginInstalled) {
      map['rtime'] = formatDate(
          DateTime.now(), [yyyy, '-', mm, '-', dd, '+', HH, ':', nn, ':', ss]);
      dynamic res = await _methodChannel.invokeMethod(statType, map);
      return res;
    } else {
      return Future.value(true);
    }
  }

  /*给h5 传递参数  justSave 只存不取 覆盖本地存储的
   ***/
  Future<void> webMethodTo(String methodKey, Map? map,
      {bool justSave = false}) async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod("webMethodTo", {
        'map': map == null || map.isEmpty ? "":convert.jsonEncode(map),
        'justSave': justSave,
        'methodKey': methodKey
      });
    }
  }

  /*从h5 获取参数
  ***/
  Future<Map?> webMethodFrom(String methodKey) async {
    if (_pluginInstalled) {
      String res = await _methodChannel
          .invokeMethod("webMethodFrom", {'methodKey': methodKey}) as String;
      if (res.isEmpty) return null;
      Map? map;
      try {
        map = convert.jsonDecode(res);
      } catch (e) {
      }
      return map;
    } else {
      return Future.value({});
    }
  }

  /*把当前控制器pop出去
  * */
  Future<void> popCurrentVC() async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod('popCurrentVC', {});
    }
  }

  /*把当前控制器pop出去
  * */
  Future<void> popCurrentVCAndGoto(Map args) async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod('popCurrentVCAndGoto', {'map': args, "json": convert.jsonEncode(args)});
    }
  }

  /*传递视频播放状态给原生
   *isDetail true 是否进入底页 false 只是点击了关闭静音按钮
   **/
  Future<void> playerStateClick(bool isVideoFull) async {
    if(_pluginInstalled) {
      await _methodChannel.invokeMethod('playerStateClick',{'isVideoFull':isVideoFull});
    }
  }
  /*发送图片到服务端 返回服务端url
  * */
  Future<String?> sendPicToUGC(String imgPath) async {
    dynamic res = await _methodChannel.invokeMethod("sendPicToUGC",{'imgPath':imgPath});
    return res == '' ? null : res;
  }

  /*存储图片到本地*/
  Future<bool> savePic(String imgUrl) async {
    return await _methodChannel.invokeMethod("savePic",{'imgUrl':imgUrl});
  }

  /*
   * flutter调用选择图片或者视频方法
   * isVideo : 是否是视频
   * count : 选择图片时设置选择数量
   * ids : 已经选择的图片、视频id
   */
  Future<List<IfengLocalMedia>> getMedia(bool isVideo, int count,{List<String>? ids}) async {
    List<IfengLocalMedia> list = [];
    if (!_pluginInstalled) {
      return Future.value(list);
    }
    List res;
    List<String> arr = ids ?? [];
    if (isVideo) {
      res = await _methodChannel.invokeMethod("getMedia", {"type": "video", "count": 1,"ids":arr});
    } else {
      res = await _methodChannel.invokeMethod("getMedia", {"type": "img", "count": count,"ids":arr});
    }
    res.map((e) {
      list.add(IfengLocalMedia.fromMap(e));
    }).toList();
    return list;
  }

  /*根据id 获取路径
  * */
  Future<IfengLocalMedia> getMediaPathWithId(String id) async {
    Map res = await _methodChannel.invokeMethod("getMediaPathWithId",{'id':id});
    return IfengLocalMedia.fromMap(res);
  }

  Future<void> userPageOffSetChange(double offset) async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod("userPageChange", {'offset': offset});
    }
  }

  Future<void> saveSP(String key, String value) async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod("saveSp", {'key': key, "value" : value});
    }
  }

  Future<String> getSP(String key, String defultValue) async {
    if (_pluginInstalled) {
      String value = await _methodChannel.invokeMethod("getSP", {'key': key});
      return value == '' ? defultValue : value;
    } else {
      return defultValue;
    }
  }

  Future<void> removeSP(String key) async {
    if (_pluginInstalled) {
      await _methodChannel.invokeMethod("removeSP", {'key': key});
    }
  }

  //给flutter 提供一个alert方法 返回值为空字符串 ，选择的为取消
  Future<String> showAlert(List<String> titles) async {
    if(!_pluginInstalled) return "";
    if(titles.isEmpty) return "";
    String choice = await _methodChannel.invokeMethod("showAlert",{"titles":titles});
    return choice;
  }

  //Android放弃音频焦点方法
  Future<void> requestAbandonAudio() async {
    if(!_pluginInstalled) return;
    String choice = await _methodChannel.invokeMethod("audioPause");
  }

  Future<String> showBigAlert(String title, String content, String leftBtn, String rightBtn) async {
    if(!_pluginInstalled) return "";
    if(title.isEmpty) return "";
    String choice = await _methodChannel.invokeMethod("showBigAlert",{"title":title, "content":content, "leftBtn": leftBtn, "rightBtn": rightBtn});
    return choice;
  }

  //存储阅读历史
  Future<bool> saveReadHistory(IfengHistoryBean bean) async {
    if (_pluginInstalled) {
      dynamic res = await _methodChannel.invokeMethod("saveReadHistory", bean.toMap());
      return res;
    } else {
      return Future.value(true);
    }
  }

  Map<String, IfengVoteResult> _subVoteDic = {};

  /*投票  voteId  questionId  optionId  staticId 统计id ，isMulti 是否多选 默认单选
  * **/
  Future<IfengVoteState> vote(IfengVoteResult result,
      {String? staticId, bool isMulti = false}) async {
    if (result.voteId.length == 0) return Future.value(IfengVoteState.fail);
    if (_pluginInstalled) {
      Map map = result.toMap();
      map['isMulti'] = isMulti;
      if (staticId != null && staticId.isNotEmpty) map['staticId'] = staticId;
      dynamic res = await _methodChannel.invokeMethod('vote', map);
      return IfengVoteStateExtension.getStateValue(res);
    } else {
      _subVoteDic[result.voteId] = result;
      _voteController.add(result);
      return Future.value(IfengVoteState.success);
    }
  }

  /*是否投票过(组)
  * **/

  Future<List<IfengVoteResult>> isGroupVoted(List<String> voteIds) async {
    if (voteIds.isEmpty) return Future.value([]);
    if (!_pluginInstalled) {
      List<IfengVoteResult> list = voteIds.map((e) {
        if (_subVoteDic[e] != null) {
          return _subVoteDic[e] as IfengVoteResult;
        } else {
          return IfengVoteResult.fromMap({"isVoted": false, "voteId": e});
        }
      }).toList();
      return Future.value(list);
    }
    dynamic res =
        await _methodChannel.invokeMethod("isVoted", {"voteIds": voteIds});
    return res
        .map((e) => IfengVoteResult.fromMap(e))
        .toList()
        .cast<IfengVoteResult>();
  }

  Future<IfengVoteResult> isVoted(String voteId) async {
    if (voteId.length == 0)
      return Future.value(
          IfengVoteResult.fromMap({'isVoted': false, 'voteId': ''}));
    List<IfengVoteResult> list = await this.isGroupVoted([voteId]);
    return list.first;
  }


  /*投票事件
  **/
  StreamController<IfengVoteResult> _voteController =
      StreamController<IfengVoteResult>.broadcast(); //plugin 没有安装的时候使用
  Stream<IfengVoteResult>? _onVoteChanged;
  Stream<IfengVoteResult> get onVoteChanged {
    if (_onVoteChanged == null) {
      if (_pluginInstalled) {
        StreamController<IfengVoteResult>? controller;
        var sub;
        controller = StreamController<IfengVoteResult>.broadcast(onListen: () {
          sub = _innerStream.where((dynamic element) {
            if (element == null) return false;
            if (element['type'] == 'vote') return true;
            return false;
          }).map((dynamic el) {
            return IfengVoteResult.fromMap(el['args']);
          }).listen((event) {
            if (controller != null) controller.add(event);
          });
          _meChannel.invokeMethod("listen", {'type': 'vote'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'vote'});
          sub.cancel();
        });
        _onVoteChanged = controller.stream;
      } else {
        _onVoteChanged = _voteController.stream;
      }
    }
    return _onVoteChanged!;
  }

  /*投票结果
  * **/
  List<String> _subList = [];
  /*
  *关注
  * followId 关注id
  * isSub 是否关注 true 关注  false 取消关注
  * type 关注类型 ，weMeida>自媒体号，source>稿源号，zhibo>直播，user>用户,ht>话题，union>视频合集
  * staticId 统计id 为空则不发统计
  * cateName 关注名称 可以为空
  * needAlert 是否关注完成弹窗提示
  *
  * type = null && staticId = null && cateName = null 则客户端不发统计
  * */
  Future<bool> subscribe(String followId,
      {String? type,
      String? staticId,
      String? cateName,
      bool isSub = true,
      bool needAlert = true}) async {
    if (followId.isEmpty) return Future.value(false);
    if (!_pluginInstalled) {
      if (isSub) {
        if (!_subList.contains(followId)) _subList.add(followId);
      } else {
        if (_subList.contains(followId)) _subList.remove(followId);
      }
      _nopluginSubscribeController.sink
          .add(IfengSubscribe.fromMap({"followId": followId, "state": isSub}));
      return Future.value(true);
    }
    Map map = Map();
    map['followId'] = followId;
    map['isSub'] = isSub;
    map['needAlert'] = needAlert;
    if (type != null) map['type'] = type;
    if (staticId != null) map['staticId'] = staticId;
    if (cateName != null) map['cateName'] = cateName;
    dynamic res = await _methodChannel.invokeMethod("subscribe", map);
    return res;
  }

  /*多条id的关注*/
  Future<List<IfengSubscribe>> isGroupSubscribe(List<String> followIds) async {
    List<IfengSubscribe> list = [];
    if (followIds.isEmpty) return Future.value(list);
    if (!_pluginInstalled) {
      followIds.map((e) {
        if (e.isNotEmpty)
          list.add(IfengSubscribe.fromMap(
              {"followId": e, "state": _subList.contains(e)}));
      }).toList();
      return Future.value(list);
    }
    List res = await _methodChannel
        .invokeMethod("isSubscribe", {"followIds": followIds});
    res.map((e) {
      list.add(IfengSubscribe.fromMap(e));
    }).toList();
    return list;
  }

  Future<bool> isSubscribe(String followId) async {
    if (followId.isEmpty) return Future.value(false);
    List<IfengSubscribe> list = await isGroupSubscribe([followId]);
    if (list.isEmpty) return false;
    return list.first.state;
  }

  StreamController<IfengSubscribe> _nopluginSubscribeController =
      StreamController<IfengSubscribe>.broadcast(); //plugin 没有安装的时候使用
  /*关注事件
  **/
  Stream<IfengSubscribe>? _onSubscribeChanged;
  Stream<IfengSubscribe> get onSubscribeChanged {
    if (_onSubscribeChanged == null) {
      if (_pluginInstalled) {
        StreamController<IfengSubscribe>? controller;
        var sub;
        controller = StreamController<IfengSubscribe>.broadcast(onListen: () {
          sub = _innerStream.where((dynamic element) {
            if (element == null) return false;
            if (element['type'] == 'subscribe') return true;
            return false;
          }).map((dynamic el) {
            return IfengSubscribe.fromMap(el['args']);
          }).listen((event) {
            if (controller != null) controller.add(event);
          });
          _meChannel.invokeMethod("listen", {'type': 'subscribe'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'subscribe'});
          sub.cancel();
        });
        _onSubscribeChanged = controller.stream;
      } else {
        _onSubscribeChanged = _nopluginSubscribeController.stream;
      }
    }
    return _onSubscribeChanged!;
  }

  /*登录成功事件
  * **/
  Stream<IfengUserInfo>? _onUserLoginStateChanged;
  Stream<IfengUserInfo> get onUserLoginStateChanged {
    if (_onUserLoginStateChanged == null) {
      if (_pluginInstalled) {
        StreamController<IfengUserInfo>? controller;
        var sub;
        controller = StreamController<IfengUserInfo>.broadcast(onListen: () {
          sub = _innerStream.where((dynamic element) {
            if (element == null) return false;
            if (element['type'] == 'user') return true;
            return false;
          }).map((dynamic el) {
            Map res = el['args'];
            IfengUserInfo info = IfengUserInfo.fromMap(res);
            _userInfo = info;
            return info;
          }).listen((event) {
            if (controller != null) controller.add(event);
          });
          _meChannel.invokeMethod("listen", {'type': 'user'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'user'});
          sub.cancel();
        });
        _onUserLoginStateChanged = controller.stream;
      } else {
        //在模式下不会变
        _onUserLoginStateChanged = StreamController<IfengUserInfo>.broadcast().stream;
      }
    }
    return _onUserLoginStateChanged!;
  }

  /*font 事件监听
  * **/
  Stream<double>? _onFontChanged;
  Stream<double> get onFontChanged {
    if (_onFontChanged == null) {
      if (_pluginInstalled) {
        StreamController<double>? controller;
        var sub;
        controller = StreamController<double>.broadcast(onListen: () {
          sub = _innerStream
              .where((dynamic element) {
                if (element == null) return false;
                if (element['type'] == 'font') return true;
                return false;
              })
              .map((dynamic el) => el['args'])
              .listen((event) {
                if (controller != null) controller.add(event);
              });
          _meChannel.invokeMethod("listen", {'type': 'font'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'font'});
          sub.cancel();
        });
        _onFontChanged = controller.stream;
      } else {
        //在模式下不会变
        _onFontChanged = StreamController<double>.broadcast().stream;
      }
    }
    return _onFontChanged!;
  }

  /*daynight 事件监听
  * **/
  Stream<IfengThemeMode>? _onDayNightChanged;
  Stream<IfengThemeMode> get onDayNightChanged {
    if (_onDayNightChanged == null) {
      if (_pluginInstalled) {
        StreamController<IfengThemeMode>? controller;
        var sub;
        controller = StreamController<IfengThemeMode>.broadcast(onListen: () {
          sub = _innerStream
              .where((dynamic element) {
                if (element == null) return false;
                if (element['type'] == 'theme') return true;
                return false;
              })
              .map((dynamic el) =>
                  IfengThemeModeExtension.modeFromStr(el['args']))
              .listen((event) {
                if (controller != null) controller.add(event);
              });
          _meChannel.invokeMethod("listen", {'type': 'theme'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'theme'});
          sub.cancel();
        });
        _onDayNightChanged = controller.stream;
      } else {
        _onDayNightChanged = StreamController<IfengThemeMode>.broadcast().stream;
      }
    }
    return _onDayNightChanged!;
  }

  /*daynight 事件监听
  * **/
  Stream<IfengWebMethod>? _onWebMethodChanged;
  Stream<IfengWebMethod> get onWebMethodChanged {
    if (_onWebMethodChanged == null) {
      if (_pluginInstalled) {
        StreamController<IfengWebMethod>? controller;
        var sub;
        controller = StreamController<IfengWebMethod>.broadcast(onListen: () {
          sub = _innerStream.where((dynamic element) {
            if (element == null) return false;
            if (element['type'] == 'webMethod') return true;
            return false;
          }).map((dynamic el) {
            String mapStr = el['args']['map'];
            Map map = mapStr == '' ? {}:convert.jsonDecode(mapStr);
            return IfengWebMethod(el['args']['methodKey'], map);
          }).listen((event) {
            if (controller != null) controller.add(event);
          });
          _meChannel.invokeMethod("listen", {'type': 'webMethod'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'webMethod'});
          sub.cancel();
        });
        _onWebMethodChanged = controller.stream;
      } else {
        _onWebMethodChanged = StreamController<IfengWebMethod>.broadcast().stream;
      }
    }
    return _onWebMethodChanged!;
  }

  /*reload按钮  点击刷新监听
  * **/
  Stream<Map>? _onReloadMethodChanged;
  Stream<Map>? get onReloadMethodChanged {
    if (_onReloadMethodChanged == null) {
      if (_pluginInstalled) {
        StreamController<Map>? controller;
        var sub;
        controller = StreamController<Map>.broadcast(onListen: () {
          sub = _innerStream.where((dynamic element) {
            if (element == null) return false;
            if (element['type'] == 'reloadMethod') return true;
            return false;
          }).listen((event) {
            if (controller != null) controller.add(event);
          });
          _meChannel.invokeMethod("listen", {'type': 'reloadMethod'});
        }, onCancel: () {
          _meChannel.invokeMethod("cancel", {'type': 'reloadMethod'});
          sub.cancel();
        });
        _onReloadMethodChanged = controller.stream;
      } else {
        _onReloadMethodChanged = StreamController<Map>.broadcast().stream;
      }
    }
    return _onReloadMethodChanged!;
  }

  /*内部的stream流
  * **/
  Stream? _eventStream;
  Stream get _innerStream {
    if (_eventStream == null) {
      _eventStream = _eventChannel.receiveBroadcastStream();
    }
    return _eventStream!;
  }
}
